from django.db import models
from courses.models import Course

class WikiPage(models.Model):
    """
    A Page in the wiki.
    
    #set up our testing stuff
    >>> from patch import Patch
    >>> from courses.models import Course
    >>> from courses.tests import setup
    >>> from tests import orig, edit, edit2
    >>> setup() # doctest:+ELLIPSIS
    G...

    >>> c = Course.objects.all()[0]
    >>> page = WikiPage(content=orig, course=c)
    >>> page.save()
    >>> page.content = edit
    >>> page.save()
    >>> page.get_rev(1) == orig
    True
    >>> page.content = orig
    >>> page.content = edit2
    >>> page.save()
    >>> Patch(edit,page.get_rev(2)).diff
    []
    """
    course = models.ForeignKey(Course)
    
    _content = models.CharField(max_length=255) #eventually, 1000
    
    content = property(lambda self: self._content)
    
    @content.setter
    def content(self, value):
        if not hasattr(self,'orig'):
            self.orig = self.content
        self._content = value
    
    def __init__(self, *args, **kwargs):
        content = kwargs.pop('content', None)
        if not content is None:
            kwargs['_content'] = content
        super(WikiPage, self).__init__(*args, **kwargs)
            
    
    #def __init__(self, *args, **kwargs):
    #    self.orig = False
    #    super(WikiPage, self).__init__(*args, **kwargs)
    
    def save(self):
        """
        Okay, so if self.orig is not set, we haven't edited the thing; so just pass.
        Otherwise, save a WikiDiff that'll get us from the new value to the last
        revision.
        """
        try:
            WikiDiff.create(edit=self.content, orig=self.orig, wikipage=self).save()
        except AttributeError:
            #self.orig is not set
            pass
        super(WikiPage, self).save()
    
    def get_rev(self, num):
        diffs = WikiDiff.objects.filter(page=self,rev__gte=num)
        copy = str(self.orig if hasattr(self, 'orig') else self.content)
        for diff in diffs:
            #eventually when we can add diffs, we'll add the diffs together
            #to make it O(patches) rather than O(copy*patches).
            #typical usage is: small patch, large copy.
            copy = Patch(diff).apply(copy)
        return copy
    
class WikiDiff(models.Model):
    """
    The diff model for wikis.  Stores a serialized diff provided by patch.py.

    """
    rev = models.IntegerField(default=0)
    page = models.ForeignKey(WikiPage, related_name='revisions')
    timestamp = models.DateTimeField(auto_now_add = True)
    content = models.CharField(max_length=255)
    
    class Meta:
        unique_together = ('rev', 'page')
    
    @classmethod
    def create(cls, orig, edit, wikipage):
        from patch import Patch
        d = WikiDiff(content=str(Patch(edit,orig)),page=wikipage)
        return d
        
    def save(self):
        if self.rev == 0:
            #new state!
            self.rev = 1
            try:
                #get the id of the last revision
                self.rev += WikiDiff.objects.filter(wiki=self.wiki).order_by('-rev')[0]
            except IndexError:
                #This is the first one!
                pass
                
        super(WikiDiff, self).save()
    
    @property
    def patch(self):
        from patch import Patch
        return Patch(self.content)
    
class CourseWiki(object):
    def __init__(self, course):
        self._course = course
    
    def all(self):
        return WikiPage.objects.filter(course=self._course)
    
    def get(self, *args, **kwargs):
        return WikiPage.get(course=self._course, *args, **kwargs)
    
    def filter(self, *args, **kwargs):
        return WikiPage.filter(course=self._course, *args, **kwargs)
    
    
    
Course.wiki = property(CourseWiki)
